import logging
import os
import sys
import argparse
import time

basedir = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, basedir)

try:
    from .mysql_utils import sql_execute
    from .mysql_utils import set_instance_read_only
    from .mysql_utils import get_transaction_from_meta
    from .mysql_utils import get_mysql_gtid
    from .mysql_utils import get_mysql_all_slave
    from .mysql_utils import sql_execute_without_close
    from .mysql_utils import lock_mysql_database
    from .mysql_utils import restore_instance_read_only
    from .mysql_utils import get_read_only_status
    from .os_utils import get_host_ip
except Exception as e:
    from mysql_utils import sql_execute
    from mysql_utils import set_instance_read_only
    from mysql_utils import get_transaction_from_meta
    from mysql_utils import get_mysql_gtid
    from mysql_utils import get_mysql_all_slave
    from mysql_utils import sql_execute_without_close
    from mysql_utils import lock_mysql_database
    from mysql_utils import restore_instance_read_only
    from mysql_utils import get_read_only_status
    from os_utils import get_host_ip

try:
    from .info_config import mysql_topology_user
    from .info_config import mysql_topology_password
    from .info_config import retry_get_transaction
    from .info_config import get_transaction_count_interval
    from .info_config import check_transaction_option
    from .info_config import compare_gtid
    from .info_config import orchestrator_http_auth_user
    from .info_config import orchestrator_http_auth_password
    from .info_config import orchestrator_url
    from .info_config import gtid_check_time
    from .info_config import gtid_check_interval

except Exception as e:
    from info_config import mysql_topology_user
    from info_config import mysql_topology_password
    from info_config import retry_get_transaction
    from info_config import get_transaction_count_interval
    from info_config import check_transaction_option
    from info_config import compare_gtid
    from info_config import orchestrator_http_auth_user
    from info_config import orchestrator_http_auth_password
    from info_config import orchestrator_url
    from info_config import gtid_check_time
    from info_config import gtid_check_interval

log_name = "{basedir}/orchestrator_graceful_takeover_processes.log".format(basedir=basedir)
log = logging.getLogger(__name__)

formatter = logging.basicConfig(
    # filename=log_name,
    level=logging.INFO,
    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    datefmt='%a, %d %b %Y %H:%M:%S')

parser = argparse.ArgumentParser(description='mysql backup command line .',
                                 usage=None,
                                 add_help=True)
parser.add_argument('--host', '-i', type=str, help='host of mysql fail instance', required=True)
parser.add_argument('--port', '-p', type=int, help='port of mysql fail instance', required=True)
parser.add_argument('--command', '-c', type=str, help='command', required=False, nargs='?', const='')

args = parser.parse_args()
mysql_demote_host = args.host
mysql_demote_port = args.port
command = args.command

local_host_ip = get_host_ip()
master_mysql_config_dict = {"database_name": None, "host": mysql_demote_host, "port": mysql_demote_port,
                            "password": mysql_topology_password,
                            "username": mysql_topology_user}


def judge_gtid(check_time, check_interval, slave_host, slave_port, master_gtid):
    gtid_check_time_run = check_time
    slave_mysql_config_dict = {"database_name": None, "host": slave_host, "port": slave_port,
                               "password": mysql_topology_password,
                               "username": mysql_topology_user}
    while gtid_check_time_run:
        slave_gtid = get_mysql_gtid(slave_mysql_config_dict)
        if slave_gtid == master_gtid:
            log.info("The instance({slave_host}:{slave_port}) gtid is the same from the master gtid. ".format(
                slave_host=slave_host, slave_port=slave_port))
            return True
        else:
            gtid_check_time_run -= 1
            time.sleep(check_interval)

    return False


def graceful_switch():
    log.info("Graceful switch cluster , demote instance is:{mysql_demote_host}:{mysql_demote_port}".format(
        mysql_demote_host=mysql_demote_host, mysql_demote_port=mysql_demote_port))

    set_instance_read_only(mysql_config_dict=master_mysql_config_dict)

    if check_transaction_option == 1:
        retry_get_transaction_count_time = retry_get_transaction
        transaction_result = get_transaction_from_meta(mysql_config_dict=master_mysql_config_dict)
        while retry_get_transaction_count_time:
            if transaction_result is not None and len(transaction_result) > 0:
                log.info(str(transaction_result))
                time.sleep(get_transaction_count_interval)
                retry_get_transaction_count_time -= 1
            else:
                break

            transaction_check_hint_info = """"Now we exit this grace switch process 
            because we detect that there are some transactions still running . 
            You can check the log : {log_name} to see what's going on . 
            If you want to force processing this progress , 
            you should config the file : {basedir}/info_config.py on {local_host_ip}
            option : 'check_transaction_option' to 0  
            to skip this step . """.format(log_name=log_name, basedir=basedir, local_host_ip=local_host_ip)
            log.info(transaction_check_hint_info)
            raise RuntimeWarning(transaction_check_hint_info)

    if compare_gtid == 1:
        master_lock_database_connect = lock_mysql_database(master_mysql_config_dict)
        master_gtid = get_mysql_gtid(master_mysql_config_dict)
        mysql_slave_list = get_mysql_all_slave(orchestrator_username=orchestrator_http_auth_user,
                                               orchestrator_password=orchestrator_http_auth_password,
                                               orchestrator_url=orchestrator_url,
                                               mysql_host=mysql_demote_host,
                                               mysql_port=mysql_demote_port)

        for inst in mysql_slave_list:
            slave_host = inst.get('Hostname')
            slave_port = inst.get('Port')
            # slave_mysql_config_dict = {"database_name": None, "host": slave_host, "port": slave_port,
            #                            "password": mysql_topology_password,
            #                            "username": mysql_topology_user}

            gtid_check_time_run = gtid_check_time
            judge_gtid_result = judge_gtid(check_time=gtid_check_time_run, check_interval=gtid_check_interval,
                                           slave_host=slave_host,
                                           slave_port=slave_port, master_gtid=master_gtid)
            # while gtid_check_time_run:
            #     slave_gtid = get_mysql_gtid(slave_mysql_config_dict)
            #     if slave_gtid == master_gtid:
            #         log.info("The instance({slave_host}:{slave_port}) gtid is the same from the master gtid. ".format(
            #             slave_host=slave_host, slave_port=slave_port))
            #         break
            #     else:
            #         gtid_check_time_run -= 1
            #         time.sleep(gtid_check_interval)
            if not judge_gtid_result:
                info_heads_up = """Now we detect that the gtid of slave instance({slave_inst}) 
                is different from the demote master instance({mysql_demote_host}:{mysql_demote_port}).
                and now we raise a RuntimeWarning exception to avoid mistake to try to maintain the data consistence . 
                If you confirm this is not an issue and still want to do a switch , 
                you should config the file : {basedir}/info_config.py on {local_host_ip} option compare_gtid to 0 
                to skip this gtid check step . """.format(slave_inst=str(inst), mysql_demote_host=mysql_demote_host,
                                                          mysql_demote_port=mysql_demote_port,
                                                          basedir=basedir, local_host_ip=local_host_ip)
                log.info(info_heads_up)
                raise RuntimeWarning(info_heads_up)

        master_lock_database_connect.close()


def main():
    super_read_only_status, read_only_status = get_read_only_status(mysql_config_dict=master_mysql_config_dict)

    try:
        graceful_switch()
    except Exception as e:
        restore_instance_read_only(master_mysql_config_dict, super_read_only_status, read_only_status)
        raise e


if __name__ == "__main__":
    sys.exit(main())
    # sys.exit(main1())

# def main1():
#     master_mysql_config_dict = {"database_name": None, "host": mysql_demote_host, "port": mysql_demote_port,
#                                 "password": mysql_topology_password,
#                                 "username": mysql_topology_user}
#     lock_database_sql = "flush tables with read lock ; "
#     master_lock_database_connect = sql_execute_without_close(sql_to_execute=lock_database_sql,
#                                                              mysql_config_dict=master_mysql_config_dict)
#     time.sleep(500)
#     print("hehe , haha")
